/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bibliOnline.task;

import bibliOnline.db.DBConnection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 *
 * @author luca
 */
public class ExpiringLoanTask implements Runnable {

    public static final String SQL =
	    "SELECT USERNAME,   EMAIL,  BOOK_ID,    TITLE,  BEGIN "
	    + "FROM UNNOTIFIED_EXPIRING_LOAN";
    public static final String TASK_NAME = "prestito in scadenza";
    public static final String SUBJECT = "BibliOnline - " + TASK_NAME;
    private Properties mailProperties;
    private Session session;
    private PreparedStatement statement;
    private ResultSet result;
    private int MAX_RETRY;
    private long RETRY_WAIT;

    public ExpiringLoanTask(Properties systemProperties) {
	mailProperties = System.getProperties();
	mailProperties.put("mail.smtp.host", systemProperties.get("mail.host"));
	mailProperties.put("mail.from", systemProperties.get("mail.from"));
	session = Session.getDefaultInstance(mailProperties, null);
	try {
	    MAX_RETRY = Integer.parseInt(systemProperties.get("mail.retry.attempts").toString());
	} catch (Exception ex) {
	    MAX_RETRY = 2;
	}
	try {
	    RETRY_WAIT = Integer.parseInt(systemProperties.get("mail.retry.wait").toString());
	} catch (Exception ex) {
	    RETRY_WAIT = 500;
	}
    }

    @Override
    public void run() {

//	1   -	INTERROGAZIONE SQL
//	
//	eseguo l'interrogazione sql;
//	se non restituisce risultati
//	allora
//	    termino
	try {
	    statement = DBConnection.prepareStatement(SQL);
	    result = statement.executeQuery();
	    if (result.next() == false) {
		result.close();
		statement.close();
		return;
	    }
	} catch (Exception ex) {
	    Logger.getLogger(ExpiringLoanTask.class.getName()).log(Level.SEVERE, null, ex);
	}

//	memorizzo i prestiti notificate e
//	le email da spedire
	Collection<Integer> notifiedLoans;
	notifiedLoans = new ArrayList<Integer>();
	Message msg;
	Collection<Message> toSend;
	toSend = new ArrayList<Message>();

//	2   -	CREAZIONE DELLE EMAIL
//	
	try {
	    InternetAddress from, to;
	    String email, title;
	    int bookId;
	    Timestamp begin;

//	    scorro tutti i prestiti in scadenza da notificare;
//	    do-while perche' ho gia' acquisito la prima riga!
	    do {
		email = result.getString("EMAIL");
		title = result.getString("TITLE");
		bookId = result.getInt("BOOK_ID");
		begin = result.getTimestamp("BEGIN");

		msg = new MimeMessage(session);
		from = new InternetAddress(mailProperties.getProperty("mail.from"));
		to = new InternetAddress(email);

		msg.setFrom(from);
		msg.setRecipient(Message.RecipientType.TO, to);
		msg.setSubject(SUBJECT);
		msg.setText("Gentile cliente, la avvisiamo che il prestito "
			+ "del libro '" + title + "' da lei "
			+ "richiesto in data "
			+ DateFormat.getDateInstance().format(begin)
			+ " sta per scadere. Cordiali saluti.");
		msg.saveChanges();

		toSend.add(msg);
		notifiedLoans.add(bookId);
	    } while (result.next());

	    result.close();
	    statement.close();
	} catch (Exception ex) {
	    Logger.getLogger(ExpiringLoanTask.class.getName()).log(Level.SEVERE, null, ex);
	}

//	3   -	SPEDIZIONE DELLE EMAIL
//	
//	per ogni email provo MAX_RETRY tentativi,
//	poi comunque considero il task completato
	Iterator<Message> m = toSend.iterator();
	boolean emailSent;
	int attempts;
	String recipient;

	while (m.hasNext()) {
	    msg = m.next();
	    emailSent = false;
	    attempts = 0;
	    try {
		recipient = msg.getAllRecipients()[0].toString();
	    } catch (MessagingException ex) {
		recipient = "destinatario sconosciuto";
	    }

	    while (emailSent == false && attempts < MAX_RETRY) {
		try {
		    if (attempts != 0) {
			try {
			    Thread.sleep(RETRY_WAIT);
			    System.out.println("Attendo " + RETRY_WAIT/1000
				    + "s per la ritrasmissione");
			} catch (Exception e) {
			    System.out.println("Problema con la sospensione del thread; "
				    + "riprovo subito la spedizione");
			}
		    }
		    Transport.send(msg);
		    emailSent = true;
		} catch (Exception ex) {
		    System.out.println("Tentativo n." + (attempts + 1)
			    + " di spedizione email per " + TASK_NAME + " a "
			    + recipient + " fallito");
		    attempts++;
		}
	    }
	    if (emailSent == true) {
		System.out.println("Spedita email per " + TASK_NAME + " a "
			+ recipient);
	    } else {
		System.out.println("Email per " + TASK_NAME + " a "
			+ recipient + ": spedizione fallita");
	    }
	}
//	4   -	AGGIORNAMENTO DEL DB
//	
	try {
	    String updateNotifiedLoans =
		    "UPDATE LOAN_IN_PROGRESS "
		    + "SET  EXPIRING_NOTIFIED   =   1 "
		    + "WHERE    BOOK_ID     =   ?";

	    int toUpdate;
	    Iterator<Integer> i = notifiedLoans.iterator();
	    while (i.hasNext()) {
		toUpdate = i.next();
		statement = DBConnection.prepareStatement(updateNotifiedLoans);
		statement.setInt(1, toUpdate);
		statement.executeUpdate();
	    }
	    statement.close();
	} catch (Exception ex) {
	    Logger.getLogger(ExpiringLoanTask.class.getName()).log(Level.SEVERE, null, ex);
	}
    }
}
